package com.by.basicgateway.intercept.filter;

import com.alibaba.fastjson2.JSON;
import com.by.basicgateway.dto.ByGatewayAuthentication;
import com.by.basicgateway.enums.RequestorClientTypeEnum;
import com.by.toolkit.consts.WebGlobalConst;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * 自定请求头数据转换
 *
 * @author Tian Wei
 * @version 1.0
 * @date 2023/12/29 1:08 PM
 */

@Slf4j
public class CustomizeRequestHandlerFilter implements WebFilter {


    private final ServerWebExchangeMatcher requiresAuthenticationMatcher;


    public CustomizeRequestHandlerFilter(ServerWebExchangeMatcher serverWebExchangeMatcher) {
        Assert.notNull(serverWebExchangeMatcher, "requiresAuthenticationMatcher cannot be null");
        this.requiresAuthenticationMatcher = serverWebExchangeMatcher;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return this.requiresAuthenticationMatcher.matches(exchange)
                .filter(ServerWebExchangeMatcher.MatchResult::isMatch)
                .switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
                .flatMap((matchResult) -> ReactiveSecurityContextHolder.getContext()
                        .map(SecurityContext::getAuthentication)
                        .cast(ByGatewayAuthentication.class)
                        .flatMap(authentication -> {
                            RequestorClientTypeEnum requestorClientTypeEnum = authentication.getRequestorClientTypeEnum();
                            Long userId = authentication.getUserId();
                            ServerHttpRequest request = exchange.getRequest();
                            HttpHeaders headers = request.getHeaders();
                            String requestId = headers.getFirst(WebGlobalConst.REQUEST_ID);
                            log.info("[CustomizeRequestHandlerFilter][filter] requestId:[{}] headers:[{}]", requestId, JSON.toJSONString(headers));
                            request = request.mutate()
                                    .headers(h -> {
                                        //新增用户id
                                        h.add(requestorClientTypeEnum.getUserIdName(), userId.toString());
                                    })
                                    .build();
                            ServerWebExchange newExchange = exchange.mutate().request(request).build();
                            return chain.filter(newExchange);
                        })
                )
                .switchIfEmpty(chain.filter(exchange).then(Mono.empty()));
    }

}
